package io.alvin.ch02;

/**
 * 正确使用stop方法停止线程
 * Created by Alvin on 2017/7/6.
 */
public  class ThreadStopDemo {
    public static User u = new User();
    public static class User{
        private int id;
        private String name;
        public User() {
            id = 0;
            name = "0";
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User [id=" + id + ",name=" + name + "]";
        }
    }

    /**
     * 写线程，总是写入两个相同的值
     */
    public static class ChangeObjectThread extends Thread {
        /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see #start()
         * @see #stop()
         */
        @Override
        public void run() {
            while (true) {
                synchronized (u) {
                    int v = (int) (System.currentTimeMillis()/1000);
                    u.setId(v);
                    // do sth. else

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    u.setName(String.valueOf(v));
                }
                Thread.yield();
            }
        }
    }

    /**
     * 改良版。增加stopMe方法
     */
    public static class ProChangeObjectThread extends Thread {
        volatile boolean stopme = false;

        public void stopMe() {
            stopme = true;
        }

        /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see #start()
         * @see #stop()
         */
        @Override
        public void run() {
            while (true) {
                if (stopme) {
                    // 结束当前线程
                    System.out.println("exit by stop me");
                    break;
                }

                synchronized (u) {
                    int v = (int) (System.currentTimeMillis()/1000);
                    u.setId(v);
                    // do sth. else

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    u.setName(String.valueOf(v));
                }

                Thread.yield();
            }
        }
    }

    /**
     * 读线程，当读到对象的ID和NAME值不一致时，输出
     */
    public static class ReadObjectThread extends Thread {
        /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see #start()
         * @see #stop()
         */
        @Override
        public void run() {
            while(true) {
                synchronized (u) {
                    if ((u.getId() != Integer.parseInt(u.getName()))) {
                        System.out.println(u.toString());
                    }
                }
                Thread.yield();
            }
        }
    }

    /**
     * 通过测试，可以发现写线程会在不确定的时间stop，导致数据不一致
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        new ReadObjectThread().start();
        while(true) {
            // Thread t = new ChangeObjectThread();
            ProChangeObjectThread t = new ProChangeObjectThread();
            t.start();
            Thread.sleep(150);
            //t.stop();
            t.stopMe();
        }
    }
}
